﻿/**
 * \file VueCase.cs
 * \brief Classe VueCase
 * \author ARTUR Vincent
 * \author LAPERDRIX Pierre
 * \version 1.0
 */

namespace WpfJeu
{

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows.Controls;
    using System.Windows.Media.Imaging;
    using System.Windows.Media;
    using System.Windows;
    using Implem;
    using System.Windows.Input;
    using System.Windows.Shapes;


    /**
     * \class VueCase
     * \brief Vue des cases du plateau de jeu
     */
    public partial class VueCase : Canvas
    {
        /*!< Case du modèle associée à la vue*/
        private Case _square;
        /*!< Propriete accedant a l'attribut _square */
        public Case Square
        {
            get { return _square; }
            set { _square = value; }
        }

        /*!< Position de la vue sur la grille de jeu */
        private Position _pos;
        /*!< Propriete accedant a l'attribut _pos */
        public Position Pos
        {
            get { return _pos; }
            set { _pos = value; }
        }

        /*!< Image du terrain associée au type de la case */
        private Image _terrain;
        /*!< Propriete accedant a l'attribut _terrain */
        public Image Terrain
        {
            get { return _terrain; }
            set { _terrain = value; }
        }

        /*!< Liste des unités présentes sur la case */
        private List<VueUnite> _unites;
        /*!< Propriete accedant a l'attribut _unites */
        public List<VueUnite> Unites
        {
            get { return _unites; }
            set { _unites = value; }
        }

        /*!< Ellipse indiquant la présence d'unités sur la case */
        private Ellipse _forme;
        /*!< Propriete accedant a l'attribut _forme */
        public Ellipse Forme
        {
            get { return _forme; }
            set { _forme = value; }
        }

        /*!< Nombre d'unités sur la case */
        private TextBlock _nombre;
        /*!< Propriete accedant a l'attribut _nombre */
        public TextBlock Nombre
        {
            get { return _nombre; }
            set { _nombre = value; }
        }

        /*!< Routed Event permettant de dire a la grille de supprimer une VueUnite */
        public static readonly RoutedEvent SuppressionEvent = EventManager.RegisterRoutedEvent(
            "Suppression", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(VueCase));

        /*!< Propriete ajoutant/supprimant l'event SuppressionEvent */
        public event RoutedEventHandler Suppression
        {
            add { AddHandler(SuppressionEvent, value); }
            remove { RemoveHandler(SuppressionEvent, value); }
        }


        /*!< Routed Event pour que le clic sur une case soit gere par le MainWindow */
        public static readonly RoutedEvent ClickCaseEvent = EventManager.RegisterRoutedEvent(
            "ClickCase", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(VueCase));

        /*!< Propriete ajoutant/supprimant l'event ClickCaseEvent */
        public event RoutedEventHandler ClickCase
        {
            add { AddHandler(ClickCaseEvent, value); }
            remove { RemoveHandler(ClickCaseEvent, value); }
        }


       private static Uri fog =  new Uri("/WpfJeu;component/Ressources/hidden.png", UriKind.Relative);
       private static Uri contour = new Uri("/WpfJeu;component/Ressources/contour.png", UriKind.Relative);

       private Image saveHidden;
       public bool cache;

       private Image saveContour;
       public bool high;

        /**
         * \fn public VueCase(Uri b, Uri d, Case c, int x, int y)
         * \brief Constructeur de VueCase
         * \param b l'adresse de l'image source du terrain
         * \param d l'adresse de l'image source du décorateur s'il y en a un
         * \param c la case liée à cette vue
         * \param x la postion x de cette vue
         * \param y la position y de cette vue
         */
        public VueCase(Uri b, Uri d, Case c, int x, int y)
        {
            cache = false;
            high = false;
            //Initialisation de la case et de sa position
            Square = c;
            Grid.SetRow(this, x);
            Grid.SetColumn(this, y);

            //Initilisation de la taille d'une case
            int taille = 50;
            this.Height = taille;
            this.Width = taille;

            //Creation de la postion
            Pos = new Position(x, y);

            //Application de la texture de base
            Terrain = new Image();
            Terrain.Source = new BitmapImage(b);
            Terrain.Height = taille;
            Terrain.Width = taille;
            this.Children.Add(Terrain);


            //Ajout de la texture du decorateur s'il y en a un
            if (d != null)
            {
                Image deco = new Image();
                deco.Source = new BitmapImage(d);
                deco.Height = taille;
                deco.Width = taille;
                this.Children.Add(deco);
            }

            //Initialisation de la liste d'unites 
            Unites = new List<VueUnite>();

            //Initialisation d'elements d'affichage
            Forme = new Ellipse();
            Forme.Width = 20;
            Forme.Height = 20;
            Forme.Visibility = Visibility.Hidden;
            Nombre = new TextBlock();
            Nombre.Text = "1";
            Nombre.Visibility = Visibility.Hidden;
            Canvas.SetZIndex(Forme, 5);
            Canvas.SetZIndex(Nombre, 6);
            this.Children.Add(Forme);
            this.Children.Add(Nombre);

            //Image du fog
            BitmapImage hidden = new BitmapImage(fog);
            Image img = new Image();
            img.Source = hidden;
            img.Tag = "hidden";
            Canvas.SetZIndex(img, 10);

            //Image du fog
            this.saveHidden = img;
            this.saveHidden.Opacity = 0.8;
            this.Children.Add(this.saveHidden);

            //Ajout d'un ecouteur d'evenemenet sur la case
            this.MouseLeftButtonDown += new MouseButtonEventHandler(case_MouseLeftButtonDown);
            Forme.MouseLeftButtonDown += new MouseButtonEventHandler(unite_MouseLeftButtonDown);
            Nombre.MouseLeftButtonDown += new MouseButtonEventHandler(unite_MouseLeftButtonDown);

            //Positionnement de certains affichages apres la creation du Canvas
            this.Loaded += new RoutedEventHandler(VueCase_Loaded);
        }

        /**
         * \fn private void VueCase_Loaded(object sender, RoutedEventArgs e)
         * \brief Mis à jour de l'affichage après création de la vue
         * \param sender
         * \param e
         */
        private void VueCase_Loaded(object sender, RoutedEventArgs e)
        {
            //Positionnement au centre
            double left = (this.Width - Forme.Width) / 2;
            Canvas.SetLeft(Forme, left);
            double top = (this.Height - Forme.Height) / 2;
            Canvas.SetTop(Forme, top);

            left = (this.ActualWidth - Nombre.ActualWidth) / 2;
            Canvas.SetLeft(Nombre, left);
            top = (this.ActualHeight - Nombre.ActualHeight) / 2;
            Canvas.SetTop(Nombre, top);

            //Prise en charge de l'évenement
            e.Handled = true;
        }

        /**
         * \fn private void case_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
         * \brief Envoi d'un event à la MainWindow pour la prise en charge du clic sur la case
         * \param sender
         * \param e
         */
        private void case_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            //Prise en charge du click
            e.Handled = true;

            //Declenchement de l'evenement ClickEvent
            RoutedEventArgs newEventArgs = new RoutedEventArgs(VueCase.ClickCaseEvent);
            RaiseEvent(newEventArgs);
        }

        /**
         * \fn private void unite_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
         * \brief Envoi d'un event à la MainWindow pour la prise en charge du clic sur les unités
         * \param sender
         * \param e
         */
        private void unite_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (Unites.Count == 1)
            {
                //Prise en charge du click
                e.Handled = true;

                //Declenchement de l'evenement ClickEvent
                VueUnite vu = Unites.First<VueUnite>();
                RoutedEventArgs newEventArgs = new RoutedEventArgs(VueUnite.ClickUniteEvent,vu);
                RaiseEvent(newEventArgs);
            }
        }


        /**
         * \fn public void nouvelleUnite(VueUnite vu)
         * \brief Ajoute une unité à la VueCase
         * \param vu la VueUnite à ajouter
         */
        public void nouvelleUnite(VueUnite vu)
        {
            this.Unites.Add(vu);
            //Ajout du handler pour la suppresison de l'unite
            vu.Unite.SuppressionEvent += suppressionUnite;

            if (this.Unites.Count == 1)
            {
                Forme.Visibility = Visibility.Visible;
                Forme.Fill = new SolidColorBrush(vu.Unite.JoueurProprietaire.Couleur);
                Nombre.Visibility = Visibility.Visible;
            }
            else 
            {
                Nombre.Text = this.Unites.Count.ToString();
                if (this.Unites.Count <= 5)
                {
                    Forme.Height += 5;
                    Forme.Width += 5;

                    double left = (this.Width - Forme.Width) / 2;
                    Canvas.SetLeft(Forme, left);
                    double top = (this.Height - Forme.Height) / 2;
                    Canvas.SetTop(Forme, top);
                }
            }
            unhideVisible();
           

        }

        /**
         * \fn public void departUnite(VueUnite vu)
         * \brief Supprime une unité de la VueCase
         * \param vu la VueUnite à supprimer
         */
        public void departUnite(VueUnite vu)
        {
            this.Unites.Remove(vu);
            //Suppression du handler
            vu.Unite.SuppressionEvent -= suppressionUnite;

            if (this.Unites.Count == 0)
            {
                Forme.Visibility = Visibility.Hidden;
                Nombre.Visibility = Visibility.Hidden;
            }
            else 
            {
                Nombre.Text = this.Unites.Count.ToString();
                if (this.Unites.Count <= 4)
                {
                    Forme.Height -= 5;
                    Forme.Width -= 5;

                    double left = (this.Width - Forme.Width) / 2;
                    Canvas.SetLeft(Forme, left);
                    double top = (this.Height - Forme.Height) / 2;
                    Canvas.SetTop(Forme, top);
                }
            }

            
        }

        /**
         * \fn public void ajoutVille(VueVillePrincipale vvp)
         * \brief Ajoute une ville à la VueCase
         * \param vvp la VueVillePrincpale à ajouter
         */
        public void ajoutVille(VueVillePrincipale vvp)
        {
            this.Children.Add(vvp);
            int xU = vvp.Ville.PositCentrale.X;
            int yU = vvp.Ville.PositCentrale.Y;
            for (int i = xU - 3; i <= xU + 3; i++)
            {
                for (int j = yU - 3; j <= yU + 3; j++)
                {
                    Position tmp = new Position(i, j);
                    if (MainWindow.all.ContainsKey(tmp) && tmp.distance(vvp.Ville.PositCentrale) <= 3 && MainWindow.all[tmp].cache)
                    {
                        MainWindow.all[tmp].unhide();
                    }
                }
            }
        }


        /**
         * \fn public void ajoutVille(VueVilleExpansion vve)
         * \brief Ajoute une expansion de ville à la VueCase
         * \param vve la VueVilleExpansion à ajouter
         */
        public void ajoutVille(VueVilleExpansion vve)
        {
            this.Children.Add(vve);
            int xU = vve.Pos.X;
            int yU = vve.Pos.Y;
            for (int i = xU - 3; i <= xU + 3; i++)
            {
                for (int j = yU - 3; j <= yU + 3; j++)
                {
                    Position tmp = new Position(i, j);
                    if (MainWindow.all.ContainsKey(tmp) && tmp.distance(vve.Pos) <= 3 && MainWindow.all[tmp].cache)
                    {
                        MainWindow.all[tmp].unhide();
                    }
                }
            }
        }

        /**
         * \fn public void suppressionUnite(object sender, Unite.SuppressionEventArgs args)
         * \brief Envoi d'un event à la MainWindow pour la suppression d'une unité vaincue
         * \param sender
         * \param args l'unité ayant déclenché l'event
         */
        public void suppressionUnite(object sender, Unite.SuppressionEventArgs args)
        {
            //On trouve la VueUnite associe
            VueUnite vu = null;
            foreach (VueUnite v in Unites)
            {
                if (v.Unite == args.unite)
                {
                    vu = v;
                }
            }

            //Envoie a la grille de la commande de suppression de la Vue
            RoutedEventArgs newEventArgs = new RoutedEventArgs(VueCase.SuppressionEvent, vu);
            RaiseEvent(newEventArgs);
        }

        
        /**
         * \fn public void unhideVisible()
         * \brief Dé-cache les cases visibles depuis la case courante
         */
        public void unhideVisible()
        {

            // Enleve le brouillard autour des unites
            foreach (VueUnite vu in Unites)
            {
                int xU = vu.Unite.Posit.X;
                int yU = vu.Unite.Posit.Y;
                for (int i = xU - 3; i <= xU + 3; i++)
                {
                    for (int j = yU - 3; j <= yU + 3; j++)
                    {
                        Position tmp = new Position(i, j);
                        if (MainWindow.all.ContainsKey(tmp) && tmp.distance(vu.Unite.Posit) <= 3 && MainWindow.all[tmp].cache)
                        {
                            MainWindow.all[tmp].unhide();
                        }
                    }
                }
            }

            // Enleve le brouillard autour des villes
            foreach (UIElement vvp in this.Children)
            {
                if (vvp is VueVillePrincipale)
                {
                    VueVillePrincipale vvp2 = (VueVillePrincipale)vvp;
                    int xU = vvp2.Ville.PositCentrale.X;
                    int yU = vvp2.Ville.PositCentrale.Y;
                    for (int i = xU - 4; i <= xU + 4; i++)
                    {
                        for (int j = yU - 4; j <= yU + 4; j++)
                        {
                            Position tmp = new Position(i, j);
                            if (MainWindow.all.ContainsKey(tmp) && tmp.distance(vvp2.Ville.PositCentrale) <= 4 && MainWindow.all[tmp].cache)
                            {
                                MainWindow.all[tmp].unhide();
                            }
                        }
                    }
                }
            }
        }

        /**
         * \fn public void hide()
         * \brief Cache la vue courante
         */
        public void hide()
        {
            saveHidden.Visibility = Visibility.Visible;
            Forme.Visibility = Visibility.Hidden;
            Nombre.Visibility = Visibility.Hidden;
            cache = true;
        }

        /**
         * \fn public void unhide()
         * \brief Dé-cache la vue courante
         */
        public void unhide()
        {
            saveHidden.Visibility = Visibility.Collapsed;
            if (this.Unites.Count > 0)
            {
                Forme.Visibility = Visibility.Visible;
                Nombre.Visibility = Visibility.Visible;
            }
            cache = false;
        }

        /**
         * \fn public void highlight()
         * \brief Met en valeur la case courante
         */ 
        public void highlight()
        {
            BitmapImage highl = new BitmapImage(contour);
            Image img = new Image();
            img.Source = highl;
            img.Tag = "highlighted";
            this.Children.Add(img);
            this.saveContour = img;
            high = true;
        }

        /**
         * \fn public void unhighlight()
         * \brief Enleve le contour de la case
         */
        public void unhighlight()
        {
            this.Children.Remove(saveContour);
            high = false;
        }


    }
}
